#ifndef VL_PICOTHREADS_HPP
#define VL_PICOTHREADS_HPP

#include "pcl/pcl.hpp"
#include "list.hpp"
#include "macros.hpp"
#include "log.hpp"

namespace vl
{

struct picothread : vl::list_node<picothread>, pcl::coro
{
	picothread()
	: pcl::coro(0)
	{
	}
	
	~picothread()
	{
		unlink();
	}
};

struct roundrobin_scheduler : pcl::coro
{
	void go()
	{
		while(!threads.empty())
		{
			sweep();
		}
	}
	
	void sweep()
	{
		FOREACH_DELETE(vl::list<picothread>, i, threads)
		{
			i->call();
			if(i->is_done())
			{
				threads.erase(i);
			}
		}
	}
	
	void schedule(picothread* thread)
	{
		threads.push_back(thread);
	}
	
	~roundrobin_scheduler()
	{
	}
		
	vl::list<picothread> threads;
};

template<typename ValueT>
struct generator : picothread
{
	ValueT _value;
};

template<typename ValueT>
struct generator_iterator
{
	generator_iterator()
	: gen(0)
	{
	}
	
	generator_iterator(generator<ValueT>* gen)
	: gen(gen)
	{
		next();
	}
	
	~generator_iterator()
	{
		delete gen;
	}
	
	bool operator==(generator_iterator const& rhs)
	{
		return gen == rhs.gen;
	}
	
	bool operator!=(generator_iterator const& rhs)
	{
		return !(*this == rhs);
	}
	
	void next()
	{
		gen->call();
		if(gen->is_done())
		{
			delete gen;
			gen = 0;
		}
	}
	
	ValueT const& operator*()
	{
		return gen->_value;
	}
	
	generator_iterator& operator++()
	{
		next();
		return *this;
	}
	
	generator<ValueT>* gen;
};

//#define PT_CheckIfDone() if(this->done) throw picothread::break_exception()

#define PT_Resume() pcl::resume() //; PT_CheckIfDone()

#define PT_WaitUntil(c_) while(!(c_)) PT_Resume()

#define PT_Yield(v_) this->_value = (v_); PT_Resume()

void test_picothreads();

}

#endif // VL_PICOTHREADS_HPP
